class Logging:
  def error( source, message ):
    # logError(String source, String message)   This function is called by any module when an exception or error occurs. It writes the details of the error, including where it happened and what happened, to the database. This data can then be used later for debugging purposes.
    print "Error %s from %s" % message, source
    
  def message( source, message ):
    """# logMessage(String source, String message)   This function is called by any module when something relevant to debugging occurs. It is very similar to logError() in what it writes the to the database, with the difference being that use of this function does not necessarily indicate an error has occurred. The data this function collects, like logError()'s data, can be used later on for debugging, but the content of these messages are generic in nature, not any cause for alarm."""
    print "Message %s from %s" % ( message, source )
    
  error = staticmethod(error)
  message = staticmethod(message)

class PublicFunctions: # PublicFunctions:
  
  def startSimulator( XMLPath ):
    print "bool startSimulator(String XMLPath)   This function is called by module 2 after it has generated the configuration model. The function then locates the XML files via the provided parameter and kicks off the simulation as well as prepares for output data. Note that if this function cannot locate the XML files, in addition to returning false instead of true, it will also throw an exception via the logError() function (also part of module 3)."
    
  def jsimEventLog( runID, time, data ):
    print "jsimEventLog(int runID, int time, String data)   This function is called by the simulation (colloquially referred to as module 5) whenever it has a new piece of simulation data. When it does have new output data for a particular run, it identifies the run by its runID (for the case when multiple simulations are being executed concurrently), the order the event comes in for this simulation via some sort of timestamp, as well as the data itself."
    
  def jsimCompleted( runID ):
    print "jsimCompleted(int runID)   This function is called by the simulation upon completion. At this point, relevant summary statistics can be calculated and bulky, raw, intermediate data can be dropped. In addition, an email is sent out to the user informing them that the simulation has completed and that the results are ready to be viewed."
    
class CoreDB: #CoreDatabaseLibrary:
  
  def registerUser( name, email, password ):
    print "bool registerUser(String name, String email, String password)   This function is called by module 1 or 4 when either wants to register a new user. This function validates the input data and returns true upon successful entry to the database."
    if name == 'Phil' and password == '1337' and email == 'dreadflint@gmail.com':
      return 1
    else:
      return 0
    
  def authenticateUser( name, password ):
    print "bool authenticateUser(String name, String password)   This function is called by module 1 or 4 when either wants to serve a login request by a user. This function queries the database to see if the provided data matches up and returns true if so. Note that for security purposes, specific details of problems with authenticating, such as the name not existing or the password being incorrect, are not provided."
    if name == 'Phil' and password == '1337':
      return 1
    else:
      return 0
    
  def saveConfiguration( cm ):
    print "int saveConfiguration(ConfigurationModel cm)   This function is called by module 2 when it has generated a new configuration model and wishes to save it. Upon successfully saving it, it returns the id it was assigned. Upon failure, it returns -1 to indicate that an error has occurred and also uses logError() to record specific details of the problem."
    
  def loadConfiguration( id ):
    print "ConfigurationModel loadConfiguration(int id)   This function is called by module 2 when it wants to access a configuration model previously saved with saveConfiguration(). If there exists a configuration model with the provided id, it is returned. Otherwise a null value is returned."
    
  def getUserConfigs( username ):
    print "List<Integer> getUserConfigs(String username)   This function is called by module 1 when it wants to show a list of saved configurations associated with a particular user. Note that the parameter could just as easily be a unique numeric id."
    
  def getUserRuns( username ):
    print "List<Integer> getUserRuns(String username)   This function is called by module 4 when it wants to show a list of completed simulation runs associated with a particular user. Note that the parameter could just as easily be a unique numeric id."
    if username == 'Phil':
      return ( 1, 2 )
    else:
      return ()
    
  def getDefaults( username ):
    print "ConfigurationModel getDefaults(String username)   This function is called by module 1 when it wants to access the default configuration model for a particular user. Note that the parameter could just as easily be a unique numeric id."
    
  def setDefaults( cm, username ):
    print "bool setDefaults(ConfigurationModel cm, String username)   This function is called by module 1 to set a particular configuration model as the default for a specific user. Note that the parameter could just as easily be a unique numeric id."
    
    
class SimulationRun( object ):
  def __init__( self, runID ):
    self.runID = int(runID)
    self.config = ( {'param': 'Docs',          'val': 5,   },
                    {'param': 'Nurses',        'val': 13,  },
                    {'param': 'Triage RNs',    'val': 2,   },
                    {'param': 'Clerks',        'val': 3,   },
                    {'param': 'Beds',          'val': 13,  },
                    {'param': 'Arrivals/Hr',   'val': 23,  },
                    {'param': 'Time (hrs)',    'val': 300, }, )
    self.results = { 'LOS': ( { 'type':'Overall',      'spread': ( 223,  396,  561,  725,  963, 1063 ), },
                              { 'type':'Triage',       'spread': (   6,    8,   10,   11,   14,   15 ), },
                              { 'type':'Registration', 'spread': (   8,    9,   11,   12,   14,   15 ), },
                              
                              { 'type':'Reg to Bed',   'spread': (  86,  159,  240,  321,  437,  486 ), },
                              { 'type':'Door to Bed',  'spread': ( 101,  177,  261,  344,  465,  516 ), },
                              { 'type':'Bed to Dispo', 'spread': ( 146,  219,  300,  380,  497,  546 ), },
                              
                              { 'type':'Acuity 1',     'spread': ( 248,  266,  286,  306,  335,  348 ), },
                              { 'type':'Acuity 2',     'spread': ( 223,  260,  300,  340,  399,  423 ), },
                              { 'type':'Acuity 3',     'spread': ( 297,  346,  400,  454,  532,  564 ), },
                              { 'type':'Acuity 4',     'spread': ( 472,  533,  600,  667,  764,  805 ), },
                              { 'type':'Acuity 5',     'spread': ( 559,  626,  700,  774,  881,  926 ), },
                              { 'type':'Acuity 6',     'spread': ( 663,  736,  817,  898, 1014, 1063 ), }, ),
                     'UTL': ( { 'resource': 'Doctors',       'spread': (0.87,  0.89,  0.90,  0.91,  0.93,  0.94), },
                              { 'resource': 'Nurses',        'spread': (0.76,  0.78,  0.80,  0.82,  0.85,  0.86), },
                              { 'resource': 'Triage Nurses', 'spread': (0.65,  0.67,  0.70,  0.73,  0.77,  0.78), },
                              { 'resource': 'Clerks',        'spread': (0.47,  0.53,  0.60,  0.67,  0.76,  0.81), },
                              { 'resource': 'Beds',          'spread': (0.37,  0.43,  0.50,  0.57,  0.66,  0.71), }, ), }
  
  def getOverallLOS( self ):      return [ datum + self.runID for datum in self.results['LOS'][0]['spread'] ]
  def getLosTriage( self ):       return [ datum + self.runID for datum in self.results['LOS'][1]['spread'] ]
  def getLosRegistration( self ): return [ datum + self.runID for datum in self.results['LOS'][2]['spread'] ]
  def getLosRegToBed( self ):     return [ datum + self.runID for datum in self.results['LOS'][3]['spread'] ]
  def getLosDoorToBed( self ):    return [ datum + self.runID for datum in self.results['LOS'][4]['spread'] ]
  def getLosBedToDispo( self ):   return [ datum + self.runID for datum in self.results['LOS'][5]['spread'] ]
  def getAcuity1LOS( self ):      return [ datum + self.runID for datum in self.results['LOS'][6]['spread'] ]
  def getAcuity2LOS( self ):      return [ datum + self.runID for datum in self.results['LOS'][7]['spread'] ]
  def getAcuity3LOS( self ):      return [ datum + self.runID for datum in self.results['LOS'][8]['spread'] ]
  def getAcuity4LOS( self ):      return [ datum + self.runID for datum in self.results['LOS'][9]['spread'] ]
  def getAcuity5LOS( self ):      return [ datum + self.runID for datum in self.results['LOS'][10]['spread'] ]
  def getAcuity6LOS( self ):      return [ datum + self.runID for datum in self.results['LOS'][11]['spread'] ]
  def getUtilDocs( self ):    return [ datum + self.runID*.001 for datum in self.results['UTL'][0]['spread'] ]
  def getUtilRNs( self ):     return [ datum + self.runID*.001 for datum in self.results['UTL'][1]['spread'] ]
  def getUtilTriRNs( self ):  return [ datum + self.runID*.001 for datum in self.results['UTL'][2]['spread'] ]
  def getUtilClerks( self ):  return [ datum + self.runID*.001 for datum in self.results['UTL'][3]['spread'] ]
  def getUtilBeds( self ):    return [ datum + self.runID*.001 for datum in self.results['UTL'][4]['spread'] ]
  
  
  def deleteRun( self ):
    print "bool deleteRun()   This function is called by module 4 when a user wants to delete a run. To provide some more robustness and security on the data, this function is an instance method of the SimulationRun class and is invoked on an existing instance of it. The alternative would be to provide the id of a run to delete, but this introduces potential issues with accidentally deleting data. By encapsulating it in the SimulationRun class, the id is protected from the moment the class is instantiated to the time it is deleted."
    
  def SetRunUser( self, username ):
    print "bool SetRunUser(String username)   This function is called by module 4 when a user creates a run anonymously and then registers after. It could in fact also be used to change a run's user from an existing user to another existing user (as opposed to a null entry to an existing user), but at this time, the only time this function should be used is when a user creates a run anonymously and then registers while viewing the results. Note that the parameter could just as easily be a unique numeric id."
    if username == 'Phil':
      return 1
    else:
      return 0
    
  def getConfiguration( self ):
    # print "ConfigurationModel getConfiguration()   This function is called by module 4 when it wants to access the configuration model used to generate a particular run."
    return self.config
  
  def getResults( self ):
    # print "List<Results> getResults()   This function is called by module 4 when it wants to access the summary data of a particular run. Note that this definition of getResults() means that all data associated with a run is being passed to module 4 at the same time. Module 4 can then filter the information as necessary, only showing the user small parts of it at once. This will be the protocol for passing information to module 4 until performance requirements or other unforeseen consequences become problems."
    return self.results
